unit RclLogL4D;

interface

uses
  RclLog,
  JclContainerIntf, JclHashMaps,
  TLoggerUnit, TLevelUnit, Classes, LogLab, SysUtils;

const
  RCLLOG_VENDOR_L4D = 'log4delphi';

type
  ILogHelp = interface
  ['{D1D6385A-07DD-4B07-8409-97B88CEA1953}']
    function GetLogger: TLogger; stdcall;
    property Logger: TLogger read GetLogger;
    
  end;
  
  TRclL4DLogVendor = class(TRclLogVendor)
  private
    FInitialized: Boolean;
    Logs: IJclStrIntfMap;
    function FindParent(AName: string): ILog;
    procedure ReleaseLogs;
  protected
    function GetInstance(AName: string): ILog; overload; override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Config(AConfigFile: string); override;
    function Description: string; override;
  end;

  TRclL4DLog = class(TRclLog, ILogHelp)
  private
    FLogger: TLogger;
  protected
    function GetLogger: TLogger; stdcall;

    procedure InternalDebug(const AMsg : String); override;
    procedure InternalError(const AMsg : String); override;
    procedure InternalFatal(const AMsg : String); override;
    procedure InternalInfo(const AMsg : String); override;
    procedure InternalTrace(AMsg: string); override;
    procedure InternalWarn(const AMsg : String); override;
    
    function InternalIsDebugEnabled: Boolean; override;
    function InternalIsErrorEnabled: Boolean; override;
    function InternalIsFatalEnabled: Boolean; override;
    function InternalIsInfoEnabled: Boolean; override;
    function InternalIsTraceEnabled: Boolean; override;
    function InternalIsWarnEnabled: Boolean; override;
  public
    constructor Create(AName: string; ALogger: TLogger); overload;

  end;

resourcestring
  sReinitialize = '%s has been initializd!';

implementation

uses
  RclStr,
  TConfiguratorUnit;

var
  LogVendor: TRclLogVendor;

constructor TRclL4DLogVendor.Create;
begin
  Logs := TJclStrIntfHashMap.Create;
end;

destructor TRclL4DLogVendor.Destroy;
begin
  ReleaseLogs;
  Logs := nil;
  inherited;
end;

procedure TRclL4DLogVendor.Config(AConfigFile: string);
var
  Loggers: TStrings;
  I: Integer;
begin
  if not FInitialized then
  begin
    TConfiguratorUnit.doPropertiesConfiguration(AConfigFile);
    Loggers := TStringList.Create;
    try
      TLogger.ListLoggers(Loggers);
      for I := 0 to Loggers.Count - 1 do
        GetInstance(Loggers.Strings[I]);
    finally
      Loggers.Free;
    end;
    FInitialized := True;
  end
//  else
//    raise ELogException.CreateFmt(sReinitialize, [RclLog_VENDOR_L4D]);
end;

function TRclL4DLogVendor.Description: string;
begin
  Result := RclLog_VENDOR_L4D;
end;

function TRclL4DLogVendor.FindParent(AName: string): ILog;
var
  Index: Integer;
begin
  Result := nil;
  if AName = '' then Exit;

  Index := Str.LastPos('.', AName);

  if Index > 0 then
  begin
    AName := Copy(AName, 1, Index - 1);

    if Supports(logs.GetValue(AName), ILog, Result) then
      Exit;
  end
  else
    AName := '';

  Result := FindParent(AName);
end;

function TRclL4DLogVendor.GetInstance(AName: string): ILog;
var
  Index: Integer;
  log: ILog;
begin
//  Index := Logs.IndexOf(AName);
  if not Supports(logs.GetValue(AName), ILog, Result) then
//  if Index = -1 then
  begin
    log := FindParent(AName);
    if log <> nil then
      Result := TRclL4DLog.Create(AName, (log as ILogHelp).Logger)
    else
      Result := TRclL4DLog.Create(AName, nil);
    Logs.PutValue(Result.Name, Result);
  end;
//  else
//    Result := TRclLog(Logs.Objects[Index]);
end;

procedure TRclL4DLogVendor.ReleaseLogs;
begin
  Logs.Clear;

  if FInitialized then
    TLogger.FreeInstances;
end;

constructor TRclL4DLog.Create(AName: string; ALogger: TLogger);
begin
  FName := AName;

  if ALogger <> nil then
    Self.FLogger := ALogger
  else
    Self.FLogger := GetLogger;
end;

procedure TRclL4DLog.InternalDebug(const AMsg : String);
begin
  getLogger.Debug(FormatMsg(AMsg));
end;

procedure TRclL4DLog.InternalError(const AMsg : String);
begin
  getLogger.Error(FormatMsg(AMsg));
end;

procedure TRclL4DLog.InternalFatal(const AMsg : String);
begin
  getLogger.Fatal(FormatMsg(AMsg));
end;

function TRclL4DLog.getLogger: TLogger;
begin
  if FLogger = nil then
    FLogger := TLogger.GetInstance(FName);
  Result := FLogger;
end;

procedure TRclL4DLog.InternalInfo(const AMsg : String);
begin
  getLogger.Info(FormatMsg(AMsg));
end;

function TRclL4DLog.InternalIsDebugEnabled: Boolean;
begin
  Result := TLevelUnit.DEBUG.IsGreaterOrEqual(getLogger.GetLevel);
end;

function TRclL4DLog.InternalIsErrorEnabled: Boolean;
begin
  Result := TLevelUnit.ERROR.IsGreaterOrEqual(getLogger.GetLevel);
end;

function TRclL4DLog.InternalIsFatalEnabled: Boolean;
begin
  Result := TLevelUnit.FATAL.IsGreaterOrEqual(getLogger.GetLevel);
end;

function TRclL4DLog.InternalIsInfoEnabled: Boolean;
begin
  Result := TLevelUnit.INFO.IsGreaterOrEqual(getLogger.GetLevel);
end;

function TRclL4DLog.InternalIsTraceEnabled: Boolean;
begin

end;

function TRclL4DLog.InternalIsWarnEnabled: Boolean;
begin
  Result := TLevelUnit.WARN.IsGreaterOrEqual(getLogger.GetLevel);
end;

procedure TRclL4DLog.InternalTrace(AMsg: string);
begin

end;

procedure TRclL4DLog.InternalWarn(const AMsg : String);
begin
  getLogger.Warn(FormatMsg(AMsg));
end;

initialization
  LogVendor := TRclL4DLogVendor.Create;
  DefaultLogVendor := LogVendor.Description;
  RegisterLogVendor(LogVendor);

finalization
  UnRegisterLogVendor(LogVendor);

end.
